home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / dbweb.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-29  |  36.3 KB  |  1,325 lines

  1. unit DBWeb;
  2.  
  3. interface
  4.  
  5. uses Windows, SysUtils, Classes, SyncObjs, HTTPApp, DB, DBTables;
  6.  
  7. type
  8.  
  9. { TWebSession }
  10.  
  11.   { defined in DBTables }
  12.   TWebSession = TSession;
  13.  
  14.   TDSTableProducer = class;
  15.  
  16. { TDSTableProducerEditor }
  17.  
  18.   TDSTableProducerEditor = class
  19.   private
  20.     FDSTableProducer: TDSTableProducer;
  21.     function GetDataSource: TDataSource;
  22.     procedure SetDataSource(DataSource: TDataSource);
  23.   public
  24.     constructor Create(DSTableProducer: TDSTableProducer);
  25.     destructor Destroy; override;
  26.     procedure Changed; virtual;
  27.     procedure PostChange; virtual;
  28.     property DSTableProducer: TDSTableProducer read FDSTableProducer;
  29.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  30.   end;
  31.  
  32. { THTTPDataLink }
  33.  
  34.   THTTPDataLink = class(TDataLink)
  35.   private
  36.     FDSTableProducer: TDSTableProducer;
  37.     FFieldCount: Integer;
  38.     FFieldMapSize: Integer;
  39.     FFieldMap: Pointer;
  40.     FModified: Boolean;
  41.     FSparseMap: Boolean;
  42.     function GetDefaultFields: Boolean;
  43.     function GetFields(I: Integer): TField;
  44.   protected
  45.     procedure ActiveChanged; override;
  46.     procedure DataSetChanged; override;
  47.     procedure DataSetScrolled(Distance: Integer); override;
  48.     procedure FocusControl(Field: TFieldRef); override;
  49.     procedure EditingChanged; override;
  50.     procedure LayoutChanged; override;
  51.     procedure RecordChanged(Field: TField); override;
  52.     procedure UpdateData; override;
  53.     function  GetMappedIndex(ColIndex: Integer): Integer;
  54.   public
  55.     constructor Create(DSTableProducer: TDSTableProducer);
  56.     destructor Destroy; override;
  57.     function AddMapping(const FieldName: string): Boolean;
  58.     procedure ClearMapping;
  59.     procedure Modified;
  60.     procedure Reset;
  61.     property DefaultFields: Boolean read GetDefaultFields;
  62.     property FieldCount: Integer read FFieldCount;
  63.     property Fields[I: Integer]: TField read GetFields;
  64.     property SparseMap: Boolean read FSparseMap write FSparseMap;
  65.   end;
  66.  
  67. { THTMLTableColumn }
  68.  
  69.   THTMLTableColumn = class(TCollectionItem)
  70.   private
  71.     FField: TField;
  72.     FFieldName: string;
  73.     FAlign: THTMLAlign;
  74.     FBgColor: THTMLBgColor;
  75.     FCustom: string;
  76.     FVAlign: THTMLVAlign;
  77.     FTitle: THTMLTableHeaderAttributes;
  78.     function GetField: TField;
  79.     function GetTableProducer: TDSTableProducer;
  80.     procedure SetAlign(Value: THTMLAlign);
  81.     procedure SetBgColor(const Value: THTMLBgColor);
  82.     procedure SetCustom(const Value: string);
  83.     procedure SetField(Value: TField);
  84.     procedure SetFieldName(const Value: string);
  85.     procedure SetTitle(Value: THTMLTableHeaderAttributes);
  86.     procedure SetVAlign(Value: THTMLVAlign);
  87.     procedure TitleChanged(Sender: TObject);
  88.   protected
  89.     function GeTDSTableProducer: TDSTableProducer;
  90.     function GetDisplayName: string; override;
  91.   public
  92.     constructor Create(Collection: TCollection); override;
  93.     destructor Destroy; override;
  94.     procedure AssignTo(Dest: TPersistent); override;
  95.     procedure Update;
  96.     property Field: TField read GetField write SetField;
  97.     property DSTableProducer: TDSTableProducer read GetTableProducer;
  98.   published
  99.     property Align: THTMLAlign read FAlign write SetAlign default haDefault;
  100.     property BgColor: THTMLBgColor read FBgColor write SetBgColor;
  101.     property Custom: string read FCustom write SetCustom;
  102.     property FieldName: string read FFieldName write SetFieldName;
  103.     property Title: THTMLTableHeaderAttributes read FTitle write SetTitle;
  104.     property VAlign: THTMLVAlign read FVAlign write SetVAlign default haVDefault;
  105.   end;
  106.  
  107.   THTMLTableColumnClass = class of THTMLTableColumn;
  108.  
  109. { THTMLTableColumns }
  110.  
  111.   THTMLColumnState = (csDefault, csCustom);
  112.  
  113.   THTMLTableColumns = class(TCollection)
  114.   private
  115.     FDSTableProducer: TDSTableProducer;
  116.     function GetColumn(Index: Integer): THTMLTableColumn;
  117.     function GetState: THTMLColumnState;
  118.     procedure SetColumn(Index: Integer; Value: THTMLTableColumn);
  119.     procedure SetState(Value: THTMLColumnState);
  120.   protected
  121.     function GetAttrCount: Integer; override;
  122.     function GetAttr(Index: Integer): string; override;
  123.     function GetItemAttr(Index, ItemIndex: Integer): string; override;
  124.     function GetOwner: TPersistent; override;
  125.     procedure Update(Item: TCollectionItem); override;
  126.   public
  127.     constructor Create(DSTableProducer: TDSTableProducer;
  128.       ColumnClass: THTMLTableColumnClass);
  129.     function  Add: THTMLTableColumn;
  130.     procedure RestoreDefaults;
  131.     procedure RebuildColumns;
  132.     property State: THTMLColumnState read GetState write SetState;
  133.     property DSTableProducer: TDSTableProducer read FDSTableProducer;
  134.     property Items[Index: Integer]: THTMLTableColumn read GetColumn write SetColumn; default;
  135.   end;
  136.  
  137. { TDSTableProducer }
  138.  
  139.   THTMLCaptionAlignment = (caDefault, caTop, caBottom);
  140.  
  141.   TCreateContentEvent = procedure (Sender: TObject; var Continue: Boolean) of object;
  142.   THTMLGetTableCaptionEvent = procedure (Sender: TObject; var Caption: string;
  143.     var Alignment: THTMLCaptionAlignment) of object;
  144.   THTMLFormatCellEvent = procedure (Sender: TObject; CellRow, CellColumn: Integer;
  145.     var BgColor: THTMLBgColor; var Align: THTMLAlign; var VAlign: THTMLVAlign;
  146.     var CustomAttrs, CellData: string) of object;
  147.   THTMLDataSetEmpty = procedure (Sender: TObject; var Continue: Boolean) of object;
  148.  
  149.   TDSTableProducer = class(TCustomContentProducer)
  150.   private
  151.     FCaption: string;
  152.     FCaptionAlignment: THTMLCaptionAlignment;
  153.     FDataLink: THTTPDataLink;
  154.     FInternalDataSource: TDataSource;
  155.     FEditor: TDSTableProducerEditor;
  156.     FColumns: THTMLTableColumns;
  157.     FHeader: TStrings;
  158.     FFooter: TStrings;
  159.     FMaxRows: Integer;
  160.     FModified: Boolean;
  161.     FLayoutLock: Integer;
  162.     FUpdateLock: Integer;
  163.     FRowAttributes: THTMLTableRowAttributes;
  164.     FTableAttributes: THTMLTableAttributes;
  165.     FOnCreateContent: TCreateContentEvent;
  166.     FOnFormatCell: THTMLFormatCellEvent;
  167.     FOnGetTableCaption: THTMLGetTableCaptionEvent;
  168.     procedure AttributeChanged(Sender: TObject);
  169.     procedure Changed;
  170.     procedure InternalLayout;
  171.     procedure SetCaption(const Value: string);
  172.     procedure SetCaptionAlignment(Value: THTMLCaptionAlignment);
  173.     procedure SetFooter(Value: TStrings);
  174.     procedure SetHeader(Value: TStrings);
  175.     procedure SetMaxRows(Value: Integer);
  176.     procedure SetRowAttributes(Value: THTMLTableRowAttributes);
  177.     procedure SetTableAttributes(Value: THTMLTableAttributes);
  178.   protected
  179.     function AcquireLayoutLock: Boolean;
  180.     procedure BeginLayout;
  181.     procedure DefineFieldMap;
  182.     function DoCreateContent: Boolean;
  183.     procedure DoFormatCell(CellRow, CellColumn: Integer; var BgColor: THTMLBgColor;
  184.       var Align: THTMLAlign; var VAlign: THTMLVAlign;
  185.       var CustomAttrs, CellData: string); dynamic;
  186.     procedure DoGetCaption(var TableCaption: string;
  187.       var CaptionAlign: THTMLCaptionAlignment); dynamic;
  188.     procedure EndLayout;
  189.     function GetDataSet: TDataSet; virtual; abstract;
  190.     function GetDataSource: TDataSource;
  191.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  192.     procedure LayoutChanged;
  193.     procedure LinkActive(Value: Boolean);
  194.     procedure SetColumns(Value: THTMLTableColumns);
  195.     procedure SetDataSet(ADataSet: TDataSet); virtual; abstract;
  196.     procedure SetDataSource(Value: TDataSource);
  197.     function StoreColumns: Boolean;
  198.     property DataLink: THTTPDataLink read FDataLink;
  199.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  200.     property InternalDataSource: TDataSource read FInTernalDataSource;
  201.     property OnCreateContent: TCreateContentEvent read FOnCreateContent
  202.       write FOnCreateContent;
  203.     property OnFormatCell: THTMLFormatCellEvent read FOnFormatCell
  204.       write FOnFormatCell;
  205.     property OnGetTableCaption: THTMLGetTableCaptionEvent
  206.       read FOnGetTableCaption write FOnGetTableCaption;
  207.   public
  208.     constructor Create(AOwner: TComponent); override;
  209.     destructor Destroy; override;
  210.     procedure BeginUpdate;
  211.     procedure EndUpdate;
  212.     property Caption: string read FCaption write SetCaption;
  213.     property CaptionAlignment: THTMLCaptionAlignment read FCaptionAlignment
  214.       write SetCaptionAlignment default caDefault;
  215.     property Columns: THTMLTableColumns read FColumns write SetColumns stored StoreColumns;
  216.     property DataSet: TDataSet read GetDataSet write SetDataSet;
  217.     property Editor: TDSTableProducerEditor read FEditor write FEditor;
  218.     property Footer: TStrings read FFooter write SetFooter;
  219.     property Header: TStrings read FHeader write SetHeader;
  220.     property MaxRows: Integer read FMaxRows write SetMaxRows default 20;
  221.     property RowAttributes: THTMLTableRowAttributes read FRowAttributes
  222.       write SetRowAttributes;
  223.     property TableAttributes: THTMLTableAttributes read FTableAttributes
  224.       write SetTableAttributes;
  225.   end;
  226.  
  227. { TQueryTableProducer }
  228.  
  229.   TQueryTableProducer = class(TDSTableProducer)
  230.   private
  231.     FQuery: TQuery;
  232.     procedure SetQuery(AQuery: TQuery);
  233.   protected
  234.     function GetDataSet: TDataSet; override;
  235.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  236.     procedure SetDataSet(ADataSet: TDataSet); override;
  237.   public
  238.     function Content: string; override;
  239.   published
  240.     property Caption;
  241.     property CaptionAlignment;
  242.     property Columns;
  243.     property Footer;
  244.     property Header;
  245.     property MaxRows;
  246.     property Query: TQuery read FQuery write SetQuery;
  247.     property RowAttributes;
  248.     property TableAttributes;
  249.     property OnCreateContent;
  250.     property OnFormatCell;
  251.     property OnGetTableCaption;
  252.   end;
  253.  
  254. { TDataSetTableProducer }
  255.  
  256.   TDataSetTableProducer = class(TDSTableProducer)
  257.   private
  258.     FDataSet: TDataSet;
  259.   protected
  260.     function GetDataSet: TDataSet; override;
  261.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  262.     procedure SetDataSet(ADataSet: TDataSet); override;
  263.   public
  264.     function Content: string; override;
  265.   published
  266.     property Caption;
  267.     property CaptionAlignment;
  268.     property Columns;
  269.     property Footer;
  270.     property Header;
  271.     property MaxRows;
  272.     property DataSet;
  273.     property RowAttributes;
  274.     property TableAttributes;
  275.     property OnCreateContent;
  276.     property OnFormatCell;
  277.     property OnGetTableCaption;
  278.   end;
  279.  
  280. function HtmlTable(DataSet: TDataSet; DataSetHandler: TDSTableProducer;
  281.   MaxRows: Integer): string;
  282.  
  283. implementation
  284.  
  285. uses
  286.   WebConst;
  287.  
  288. { Error reporting }
  289.  
  290. procedure TableError(const S: string);
  291. begin
  292.   raise Exception.Create(S);
  293. end;
  294.  
  295. { DSTableProducerEditor }
  296.  
  297. constructor TDSTableProducerEditor.Create(DSTableProducer: TDSTableProducer);
  298. begin
  299.   inherited Create;
  300.   FDSTableProducer := DSTableProducer;
  301.   FDSTableProducer.Editor := Self;
  302. end;
  303.  
  304. destructor TDSTableProducerEditor.Destroy;
  305. begin
  306.   if FDSTableProducer <> nil then FDSTableProducer.Editor := nil;
  307.   inherited Destroy;
  308. end;
  309.  
  310. procedure TDSTableProducerEditor.Changed;
  311. begin
  312. end;
  313.  
  314. procedure TDSTableProducerEditor.PostChange;
  315. begin
  316. end;
  317.  
  318. function TDSTableProducerEditor.GetDataSource;
  319. begin
  320.   if Assigned(FDSTableProducer) then
  321.     Result := FDSTableProducer.DataSource
  322.   else Result := nil;
  323. end;
  324.  
  325. procedure TDSTableProducerEditor.SetDataSource(DataSource: TDataSource);
  326. begin
  327.   if Assigned(FDSTableProducer) then
  328.     FDSTableProducer.DataSource := DataSource;
  329. end;
  330.  
  331. { THTMLTableColumn }
  332.  
  333. constructor THTMLTableColumn.Create(Collection: TCollection);
  334. var
  335.   DataSetHandler: TDSTableProducer;
  336. begin
  337.   DataSetHandler := nil;
  338.   if (Collection <> nil) and (Collection is THTMLTableColumns) then
  339.     DataSetHandler := THTMLTableColumns(Collection).DSTableProducer;
  340.   if DataSetHandler <> nil then
  341.     DataSetHandler.BeginLayout;
  342.   try
  343.     inherited Create(Collection);
  344.     FTitle := THTMLTableHeaderAttributes.Create(nil);
  345.     FTitle.OnChange := TitleChanged;
  346.   finally
  347.     if DataSetHandler <> nil then
  348.       DataSetHandler.EndLayout;
  349.   end;
  350. end;
  351.  
  352. destructor THTMLTableColumn.Destroy;
  353. begin
  354.   FTitle.Free;
  355.   inherited Destroy;
  356. end;
  357.  
  358. procedure THTMLTableColumn.AssignTo(Dest: TPersistent);
  359. begin
  360.   if Dest is THTMLTableColumn then
  361.   begin
  362.     if Assigned(Collection) then Collection.BeginUpdate;
  363.     try
  364.       with THTMLTableColumn(Dest) do
  365.       begin
  366.         FieldName := Self.FieldName;
  367.         Align := Self.Align;
  368.         BgColor := Self.BgColor;
  369.         VAlign := Self.VAlign;
  370.         Title := Self.Title;
  371.       end;
  372.     finally
  373.       if Assigned(Collection) then Collection.EndUpdate;
  374.     end;
  375.   end else inherited AssignTo(Dest);
  376. end;
  377.  
  378. function THTMLTableColumn.GetField: TField;
  379. var
  380.   HTTPDSHandler: TDSTableProducer;
  381. begin
  382.   HTTPDSHandler := GetDSTableProducer;
  383.   if (FField = nil) and (FFieldName <> '') and Assigned(HTTPDsHandler) and
  384.     Assigned(HTTPDSHandler.DataLink.DataSet) then
  385.   with HTTPDSHandler.Datalink.Dataset do
  386.     if Active or (not DefaultFields) then
  387.       SetField(FindField(FieldName));
  388.   Result := FField;
  389. end;
  390.  
  391. function THTMLTableColumn.GetTableProducer: TDSTableProducer;
  392. begin
  393.   if Assigned(Collection) and (Collection is THTMLTableColumns) then
  394.     Result := THTMLTableColumns(Collection).DSTableProducer
  395.   else
  396.     Result := nil;
  397. end;
  398.  
  399. function THTMLTableColumn.GetDSTableProducer: TDSTableProducer;
  400. begin
  401.   if Assigned(Collection) and (Collection is THTMLTableColumns) then
  402.     Result := THTMLTableColumns(Collection).DSTableProducer
  403.   else Result := nil;
  404. end;
  405.  
  406. function THTMLTableColumn.GetDisplayName: string;
  407. begin
  408.   if FFieldName <> '' then
  409.     Result := FFieldName
  410.   else Result := inherited GetDisplayName;  
  411. end;
  412.  
  413. procedure THTMLTableColumn.SetAlign(Value: THTMLAlign);
  414. begin
  415.   if Value <> FAlign then
  416.   begin
  417.     FAlign := Value;
  418.     Changed(False);
  419.   end;
  420. end;
  421.  
  422. procedure THTMLTableColumn.SetBgColor(const Value: THTMLBgColor);
  423. begin
  424.   if Value <> FBgColor then
  425.   begin
  426.     FBgColor := Value;
  427.     Changed(False);
  428.   end;
  429. end;
  430.  
  431. procedure THTMLTableColumn.SetCustom(const Value: string);
  432. begin
  433.   if Value <> FCustom then
  434.   begin
  435.     FCustom := Value;
  436.     Changed(False);
  437.   end;
  438. end;
  439.  
  440. procedure THTMLTableColumn.SetField(Value: TField);
  441. begin
  442.   if Value <> FField then
  443.   begin
  444.     FField := Value;
  445.     if Assigned(Value) then
  446.       FFieldName := Value.FieldName;
  447.     Changed(False);
  448.   end;
  449. end;
  450.  
  451. procedure THTMLTableColumn.SetFieldName(const Value: string);
  452. var
  453.   AField: TField;
  454.   DataSetHandler: TDSTableProducer;
  455. begin
  456.   AField := nil;
  457.   DataSetHandler := GetDSTableProducer;
  458.   if Assigned(DataSetHandler) and Assigned(DataSetHandler.DataLink.DataSet) and
  459.     not (csLoading in DataSetHandler.ComponentState) and (Value <> '') then
  460.       AField := DataSetHandler.DataLink.DataSet.FindField(Value); { no exceptions }
  461.   FFieldName := Value;
  462.   SetField(AField);
  463.   Changed(False);
  464. end;
  465.  
  466. procedure THTMLTableColumn.SetTitle(Value: THTMLTableHeaderAttributes);
  467. begin
  468.   FTitle.Assign(Value);
  469. end;
  470.  
  471. procedure THTMLTableColumn.SetVAlign(Value: THTMLVAlign);
  472. begin
  473.   if Value <> FVAlign then
  474.   begin
  475.     FVAlign := Value;
  476.     Changed(False);
  477.   end;
  478. end;
  479.  
  480. procedure THTMLTableColumn.TitleChanged(Sender: TObject);
  481. begin
  482.   Changed(False);
  483. end;
  484.  
  485. procedure THTMLTableColumn.Update;
  486. begin
  487.   GetField;
  488. end;
  489.  
  490. type
  491.   TDefaultHTMLTableColumn = class(THTMLTableColumn)
  492.     constructor Create(Collection: TCollection); override;
  493.   end;
  494.  
  495. { TDefaultHTMLTableColumn }
  496.  
  497. constructor TDefaultHTMLTableColumn.Create(Collection: TCollection);
  498. begin
  499.   inherited Create(Collection);
  500. end;
  501.  
  502. { THTMLTableColumns }
  503.  
  504. constructor THTMLTableColumns.Create(DSTableProducer: TDSTableProducer;
  505.   ColumnClass: THTMLTableColumnClass);
  506. begin
  507.   inherited Create(ColumnClass);
  508.   FDSTableProducer := DSTableProducer;
  509. end;
  510.  
  511. function THTMLTableColumns.Add: THTMLTableColumn;
  512. begin
  513.   Result := THTMLTableColumn(inherited Add);
  514. end;
  515.  
  516. function THTMLTableColumns.GetColumn(Index: Integer): THTMLTableColumn;
  517. begin
  518.   Result := THTMLTableColumn(inherited Items[Index]);
  519. end;
  520.  
  521. function THTMLTableColumns.GetState: THTMLColumnState;
  522. begin
  523.   Result := THTMLColumnState((Count > 0) and not (Items[0] is TDefaultHTMLTableColumn));
  524. end;
  525.  
  526. procedure THTMLTableColumns.RestoreDefaults;
  527. begin
  528. end;
  529.  
  530. procedure THTMLTableColumns.RebuildColumns;
  531. var
  532.   I: Integer;
  533. begin
  534.   Clear;
  535.   if Assigned(FDSTableProducer) and Assigned(FDSTableProducer.DataSource) and
  536.     Assigned(FDSTableProducer.Datasource.Dataset) then
  537.   begin
  538.     FDSTableProducer.BeginLayout;
  539.     try
  540.       with FDSTableProducer.Datasource.Dataset do
  541.         for I := 0 to FieldCount - 1 do
  542.           Add.Field := Fields[I];
  543.     finally
  544.       FDSTableProducer.EndLayout;
  545.     end;
  546.     for I := 0 to Count - 1 do Items[I].Update;
  547.   end;
  548. end;
  549.  
  550. procedure THTMLTableColumns.SetColumn(Index: Integer; Value: THTMLTableColumn);
  551. begin
  552.   Items[Index].Assign(Value);
  553. end;
  554.  
  555. procedure THTMLTableColumns.SetState(Value: THTMLColumnState);
  556. begin
  557.   if Value <> State then
  558.   begin
  559.     if Value = csDefault then
  560.       Clear
  561.     else
  562.       RebuildColumns;
  563.   end;
  564. end;
  565.  
  566. { Design-time support }
  567. function THTMLTableColumns.GetAttrCount: Integer;
  568. begin
  569.   Result := 2;
  570. end;
  571.  
  572. function THTMLTableColumns.GetAttr(Index: Integer): string;
  573. begin
  574.   case Index of
  575.     0: Result := sFieldNameColumn;
  576.     1: Result := sFieldTypeColumn;
  577.   else
  578.     Result := '';
  579.   end;
  580. end;
  581.  
  582. function THTMLTableColumns.GetItemAttr(Index, ItemIndex: Integer): string;
  583. begin
  584.   case Index of
  585.     0: Result := Items[ItemIndex].DisplayName;
  586.     1:
  587.       with Items[ItemIndex] do
  588.         if FField <> nil then
  589.           Result := FField.ClassName
  590.         else Result := '';
  591.   else
  592.     Result := '';
  593.   end;
  594. end;
  595.  
  596. function THTMLTableColumns.GetOwner: TPersistent;
  597. begin
  598.   Result := FDSTableProducer;
  599. end;
  600.  
  601. procedure THTMLTableColumns.Update(Item: TCollectionItem);
  602. begin
  603.   if (FDSTableProducer <> nil) and
  604.     not (csLoading in FDSTableProducer.ComponentState) then
  605.     if Item = nil then
  606.       FDSTableProducer.LayoutChanged
  607.     else if FDSTableProducer.Editor <> nil then
  608.       FDSTableProducer.Editor.PostChange;
  609. end;
  610.  
  611. { THTTPDataLink }
  612.  
  613. const
  614.   MaxMapSize = (MaxInt div 2) div SizeOf(Integer);  { 250 million }
  615.  
  616. type
  617.   TIntArray = array[0..MaxMapSize - 1] of Integer;
  618.   PIntArray = ^TIntArray;
  619.  
  620. constructor THTTPDataLink.Create(DSTableProducer: TDSTableProducer);
  621. begin
  622.   inherited Create;
  623.   FDSTableProducer := DSTableProducer;
  624. end;
  625.  
  626. destructor THTTPDataLink.Destroy;
  627. begin
  628.   ClearMapping;
  629.   inherited Destroy;
  630. end;
  631.  
  632. function THTTPDataLink.GetDefaultFields: Boolean;
  633. var
  634.   I: Integer;
  635. begin
  636.   Result := True;
  637.   if DataSet <> nil then Result := DataSet.DefaultFields;
  638.   if Result and SparseMap then
  639.   for I := 0 to FFieldCount - 1 do
  640.     if PIntArray(FFieldMap)^[I] < 0 then
  641.     begin
  642.       Result := False;
  643.       Exit;
  644.     end;
  645. end;
  646.  
  647. function THTTPDataLink.GetFields(I: Integer): TField;
  648. begin
  649.   if (0 <= I) and (I < FFieldCount) and (PIntArray(FFieldMap)^[I] >= 0) then
  650.     Result := DataSet.Fields[PIntArray(FFieldMap)^[I]]
  651.   else
  652.     Result := nil;
  653. end;
  654.  
  655. function THTTPDataLink.AddMapping(const FieldName: string): Boolean;
  656. var
  657.   Field: TField;
  658.   NewSize: Integer;
  659. begin
  660.   Result := True;
  661.   if FFieldCount >= MaxMapSize then TableError(STooManyColumns);
  662.   if SparseMap then
  663.     Field := DataSet.FindField(FieldName)
  664.   else
  665.     Field := DataSet.FieldByName(FieldName);
  666.  
  667.   if FFieldCount = FFieldMapSize then
  668.   begin
  669.     NewSize := FFieldMapSize;
  670.     if NewSize = 0 then
  671.       NewSize := 8
  672.     else
  673.       Inc(NewSize, NewSize);
  674.     if (NewSize < FFieldCount) then
  675.       NewSize := FFieldCount + 1;
  676.     if (NewSize > MaxMapSize) then
  677.       NewSize := MaxMapSize;
  678.     ReallocMem(FFieldMap, NewSize * SizeOf(Integer));
  679.     FFieldMapSize := NewSize;
  680.   end;
  681.   if Assigned(Field) then
  682.   begin
  683.     PIntArray(FFieldMap)^[FFieldCount] := Field.Index;
  684.     Field.FreeNotification(FDSTableProducer);
  685.   end
  686.   else
  687.     PIntArray(FFieldMap)^[FFieldCount] := -1;
  688.   Inc(FFieldCount);
  689. end;
  690.  
  691. procedure THTTPDataLink.ActiveChanged;
  692. begin
  693.   FDSTableProducer.LinkActive(Active);
  694. end;
  695.  
  696. procedure THTTPDataLink.ClearMapping;
  697. begin
  698.   if FFieldMap <> nil then
  699.   begin
  700.     FreeMem(FFieldMap, FFieldMapSize * SizeOf(Integer));
  701.     FFieldMap := nil;
  702.     FFieldMapSize := 0;
  703.     FFieldCount := 0;
  704.   end;
  705. end;
  706.  
  707. procedure THTTPDataLink.Modified;
  708. begin
  709.   FModified := True;
  710. end;
  711.  
  712. procedure THTTPDataLink.DataSetChanged;
  713. begin
  714.   FDSTableProducer.Changed;
  715.   FModified := False;
  716. end;
  717.  
  718. procedure THTTPDataLink.DataSetScrolled(Distance: Integer);
  719. begin
  720. //  FGrid.Scroll(Distance);
  721. end;
  722.  
  723. procedure THTTPDataLink.LayoutChanged;
  724. begin
  725.   FDSTableProducer.LayoutChanged;
  726. end;
  727.  
  728. procedure THTTPDataLink.FocusControl(Field: TFieldRef);
  729. begin
  730. //  Not Needed
  731. end;
  732.  
  733. procedure THTTPDataLink.EditingChanged;
  734. begin
  735. //  Not Needed
  736. end;
  737.  
  738. procedure THTTPDataLink.RecordChanged(Field: TField);
  739. begin
  740. //  Not Needed
  741. end;
  742.  
  743. procedure THTTPDataLink.UpdateData;
  744. begin
  745. //  Not Needed
  746. end;
  747.  
  748. function THTTPDataLink.GetMappedIndex(ColIndex: Integer): Integer;
  749. begin
  750.   if (0 <= ColIndex) and (ColIndex < FFieldCount) then
  751.     Result := PIntArray(FFieldMap)^[ColIndex]
  752.   else
  753.     Result := -1;
  754. end;
  755.  
  756. procedure THTTPDataLink.Reset;
  757. begin
  758.   if FModified then RecordChanged(nil) else Dataset.Cancel;
  759. end;
  760.  
  761. { TDSTableProducer }
  762.  
  763. constructor TDSTableProducer.Create(AOwner: TComponent);
  764. begin
  765.   inherited Create(AOwner);
  766.   FFooter := TStringList.Create;
  767.   FHeader := TStringList.Create;
  768.   FDataLink := THTTPDataLink.Create(Self);
  769.   FInternalDataSource := TDataSource.Create(Self);
  770.   FColumns := THTMLTableColumns.Create(Self, THTMLTableColumn);
  771.   FRowAttributes := THTMLTableRowAttributes.Create(Self);
  772.   FRowAttributes.OnChange := AttributeChanged;
  773.   FTableAttributes := THTMLTableAttributes.Create(Self);
  774.   FTableAttributes.OnChange := AttributeChanged;
  775.   FMaxRows := 20;
  776.   DataSource := FInternalDataSource; // must be the last thing
  777. end;
  778.  
  779. destructor TDSTableProducer.Destroy;
  780. begin
  781.   BeginUpdate;
  782.   DataSource := nil;
  783.   FColumns.Free;
  784.   FColumns := nil;
  785.   FDataLink.Free;
  786.   FDataLink := nil;
  787.   FInternalDataSource.Free;
  788.   FInternalDataSource := nil;
  789.   FRowAttributes.Free;
  790.   FTableAttributes.Free;
  791.   FFooter.Free;
  792.   FHeader.Free;
  793.   inherited Destroy;
  794. end;
  795.  
  796. function TDSTableProducer.AcquireLayoutLock: Boolean;
  797. begin
  798.   Result := (FLayoutLock = 0) and (FUpdateLock = 0);
  799.   if Result then BeginLayout;
  800. end;
  801.  
  802. procedure TDSTableProducer.AttributeChanged(Sender: TObject);
  803. begin
  804.   Changed;
  805. end;
  806.  
  807. procedure TDSTableProducer.BeginLayout;
  808. begin
  809.   BeginUpdate;
  810.   if FLayoutLock = 0 then FColumns.BeginUpdate;
  811.   Inc(FLayoutLock);
  812. end;
  813.  
  814. procedure TDSTableProducer.BeginUpdate;
  815. begin
  816.   Inc(FUpdateLock);
  817. end;
  818.  
  819. procedure TDSTableProducer.Changed;
  820. begin
  821.   if (FUpdateLock = 0) and Assigned(FEditor) then
  822.     FEditor.Changed
  823.   else FModified := True;
  824. end;
  825.  
  826. procedure TDSTableProducer.DefineFieldMap;
  827. var
  828.   I: Integer;
  829. begin
  830.   if FColumns.State = csCustom then
  831.   begin   { Build the column/field map from the column attributes }
  832.     DataLink.SparseMap := True;
  833.     for I := 0 to FColumns.Count - 1 do
  834.       FDataLink.AddMapping(FColumns[I].FieldName);
  835.   end
  836.   else   { Build the column/field map from the field list order }
  837.   begin
  838.     FDataLink.SparseMap := False;
  839.     with Datalink.Dataset do
  840.       for I := 0 to FieldCount - 1 do
  841.         with Fields[I] do Datalink.AddMapping(FieldName);
  842.   end;
  843. end;
  844.  
  845. function TDSTableProducer.DoCreateContent: Boolean;
  846. begin
  847.   Result := True;
  848.   if Assigned(FOnCreateContent) then
  849.     FOnCreateContent(Self, Result);
  850. end;
  851.  
  852. procedure TDSTableProducer.DoFormatCell(CellRow, CellColumn: Integer;
  853.   var BgColor: THTMLBgColor; var Align: THTMLAlign; var VAlign: THTMLVAlign;
  854.   var CustomAttrs, CellData: string);
  855. begin
  856.   if Assigned(FOnFormatCell) then
  857.     FOnFormatCell(Self, CellRow, CellColumn, BgColor, Align, VAlign, CustomAttrs, CellData);
  858. end;
  859.  
  860. procedure TDSTableProducer.DoGetCaption(var TableCaption: string;
  861.   var CaptionAlign: THTMLCaptionAlignment);
  862. begin
  863.   TableCaption := FCaption;
  864.   CaptionAlign := FCaptionAlignment;
  865.   if Assigned(FOnGetTableCaption) then
  866.     FOnGetTableCaption(Self, TableCaption, CaptionAlign);
  867. end;
  868.  
  869. procedure TDSTableProducer.EndLayout;
  870. begin
  871.   if FLayoutLock > 0 then
  872.   begin
  873.     try
  874.       try
  875.         if FLayoutLock = 1 then
  876.           InternalLayout;
  877.       finally
  878.         if FLayoutLock = 1 then
  879.           FColumns.EndUpdate;
  880.       end;
  881.     finally
  882.       Dec(FLayoutLock);
  883.       EndUpdate;
  884.     end;
  885.   end;
  886. end;
  887.  
  888. procedure TDSTableProducer.EndUpdate;
  889. begin
  890.   if (FUpdateLock = 1) and Assigned(FEditor) and (FModified or
  891.     (FInternalDataSource.DataSet = nil) or
  892.     ((FInternalDataSource.DataSet <> nil) and (FInternalDataSource.State = dsInactive))) then
  893.   begin
  894.     FModified := False;
  895.     FEditor.Changed;
  896.   end;
  897.   if FUpdateLock > 0 then
  898.     Dec(FUpdateLock);
  899. end;
  900.  
  901. function TDSTableProducer.GetDataSource: TDataSource;
  902. begin
  903.   Result := FDataLink.DataSource;
  904. end;
  905.  
  906. procedure TDSTableProducer.InternalLayout;
  907. var
  908.   I, J, K: Integer;
  909.   Fld: TField;
  910.   Column: THTMLTableColumn;
  911.   SeenDefColumn: Boolean;
  912.  
  913.   function FieldIsMapped(F: TField): Boolean;
  914.   var
  915.     X: Integer;
  916.   begin
  917.     Result := False;
  918.     if F <> nil then
  919.       for X := 0 to FDatalink.FieldCount - 1 do
  920.         if FDatalink.Fields[X] = F then
  921.         begin
  922.           Result := True;
  923.           Exit;
  924.         end;
  925.   end;
  926.  
  927. begin
  928.   if (csLoading in ComponentState) then Exit;
  929.   SeenDefColumn := False;
  930.   for I := 0 to FColumns.Count - 1 do
  931.   begin
  932.     if (FColumns[I] is TDefaultHTMLTableColumn) then
  933.       SeenDefColumn := True
  934.     else
  935.       if SeenDefColumn then
  936.       begin   { We have both custom and "passthrough columns". Kill the latter }
  937.         for J := FColumns.Count-1 downto 0 do
  938.         begin
  939.           Column := FColumns[J];
  940.           if Column is TDefaultHTMLTableColumn then
  941.             Column.Free;
  942.         end;
  943.         Break;
  944.       end;
  945.   end;
  946.   FDatalink.ClearMapping;
  947.   if FDatalink.Active then DefineFieldMap;
  948.   if FColumns.State = csDefault then
  949.   begin
  950.      { Destroy columns whose fields have been destroyed or are no longer
  951.        in field map }
  952.     if (not FDataLink.Active) and (FDatalink.DefaultFields) then
  953.       FColumns.Clear
  954.     else
  955.       for J := FColumns.Count - 1 downto 0 do
  956.         with FColumns[J] do
  957.           if not Assigned(Field)
  958.             or not FieldIsMapped(Field) then Free;
  959.     I := FDataLink.FieldCount;
  960.     for J := 0 to I - 1 do
  961.     begin
  962.       Fld := FDatalink.Fields[J];
  963.       if Assigned(Fld) then
  964.       begin
  965.         K := J;
  966.          { Pointer compare is valid here because the table sets matching
  967.            column.field properties to nil in response to field object
  968.            free notifications.  Closing a dataset that has only default
  969.            field objects will destroy all the fields and set associated
  970.            column.field props to nil. }
  971.         while (K < FColumns.Count) and (FColumns[K].Field <> Fld) do
  972.           Inc(K);
  973.         if K < FColumns.Count then
  974.           Column := FColumns[K]
  975.         else
  976.         begin
  977.           Column := TDefaultHTMLTableColumn.Create(FColumns);
  978.           Column.Field := Fld;
  979.         end;
  980.       end
  981.       else
  982.         Column := TDefaultHTMLTableColumn.Create(FColumns);
  983.       Column.Index := J;
  984.     end;
  985.   end
  986.   else
  987.   begin
  988.     { Force columns to reaquire fields (in case dataset has changed) }
  989.     for I := 0 to FColumns.Count - 1 do
  990.       FColumns[I].Field := nil;
  991.   end;
  992. end;
  993.  
  994. procedure TDSTableProducer.LayoutChanged;
  995. begin
  996.   if AcquireLayoutLock then EndLayout;
  997. end;
  998.  
  999. procedure TDSTableProducer.LinkActive(Value: Boolean);
  1000. begin
  1001.   LayoutChanged;
  1002. end;
  1003.  
  1004. procedure TDSTableProducer.Notification(AComponent: TComponent; Operation: TOperation);
  1005. var
  1006.   I: Integer;
  1007. begin
  1008.   inherited Notification(AComponent, Operation);
  1009.   if (Operation = opRemove) and (FDataLink <> nil) then
  1010.     if (AComponent = DataSource)  then
  1011.       DataSource := nil
  1012.     else if (AComponent is TField) then
  1013.     begin
  1014.       BeginLayout;
  1015.       try
  1016.         for I := 0 to Columns.Count - 1 do
  1017.           with Columns[I] do
  1018.             if Field = AComponent then
  1019.               Field := nil;
  1020.       finally
  1021.         EndLayout;
  1022.       end;
  1023.     end;
  1024. end;
  1025.  
  1026. procedure TDSTableProducer.SetCaption(const Value: string);
  1027. begin
  1028.   FCaption := Value;
  1029.   Changed;
  1030. end;
  1031.  
  1032. procedure TDSTableProducer.SetCaptionAlignment(Value: THTMLCaptionAlignment);
  1033. begin
  1034.   if FCaptionAlignment <> Value then
  1035.   begin
  1036.     FCaptionAlignment := Value;
  1037.     Changed;
  1038.   end;
  1039. end;
  1040.  
  1041. procedure TDSTableProducer.SetColumns(Value: THTMLTableColumns);
  1042. begin
  1043.   Columns.Assign(Value);
  1044. end;
  1045.  
  1046. procedure TDSTableProducer.SetDataSource(Value: TDataSource);
  1047. begin
  1048.   if Value = FDatalink.Datasource then Exit;
  1049.   FDataLink.DataSource := Value;
  1050.   if Value <> nil then Value.FreeNotification(Self);
  1051.   if (Owner <> nil) and not (csLoading in Owner.ComponentState) then
  1052.     LinkActive(FDataLink.Active);
  1053. end;
  1054.  
  1055. procedure TDSTableProducer.SetFooter(Value: TStrings);
  1056. begin
  1057.   FFooter.Assign(Value);
  1058.   Changed;
  1059. end;
  1060.  
  1061. procedure TDSTableProducer.SetHeader(Value: TStrings);
  1062. begin
  1063.   FHeader.Assign(Value);
  1064.   Changed;
  1065. end;
  1066.  
  1067. procedure TDSTableProducer.SetMaxRows(Value: Integer);
  1068. begin
  1069.   if FMaxRows <> Value then
  1070.   begin
  1071.     FMaxRows := Value;
  1072.     Changed;
  1073.   end;
  1074. end;
  1075.  
  1076. procedure TDSTableProducer.SetRowAttributes(Value: THTMLTableRowAttributes);
  1077. begin
  1078.   FRowAttributes.Assign(Value);
  1079. end;
  1080.  
  1081. procedure TDSTableProducer.SetTableAttributes(Value: THTMLTableAttributes);
  1082. begin
  1083.   FTableAttributes.Assign(Value);
  1084. end;
  1085.  
  1086. function TDSTableProducer.StoreColumns: Boolean;
  1087. begin
  1088.   Result := Columns.State = csCustom;
  1089. end;
  1090.  
  1091. { TQueryTableProducer }
  1092.  
  1093. function TQueryTableProducer.Content: string;
  1094. var
  1095.   Params: TStrings;
  1096.   I: Integer;
  1097.   Name: string;
  1098.   Param: TParam;
  1099. begin
  1100.   Result := '';
  1101.   if (FQuery <> nil) and (Dispatcher <> nil) then
  1102.   begin
  1103.     FQuery.Close;
  1104.     Params := nil;
  1105.     if Dispatcher.Request.MethodType = mtPost then
  1106.       Params := Dispatcher.Request.ContentFields
  1107.     else if Dispatcher.Request.MethodType = mtGet then
  1108.       Params := Dispatcher.Request.QueryFields;
  1109.     if Params <> nil then
  1110.       for I := 0 to Params.Count - 1 do
  1111.       begin
  1112.         Name := Params.Names[I];
  1113.         Param := FQuery.Params.ParamByName(Name);
  1114.         if Param <> nil then
  1115.           Param.Text := Params.Values[Name];
  1116.       end;
  1117.     FQuery.Open;
  1118.     if DoCreateContent then
  1119.       Result := FHeader.Text + HTMLTable(FQuery, Self, FMaxRows) + FFooter.Text;
  1120.   end;
  1121. end;
  1122.  
  1123. function TQueryTableProducer.GetDataSet: TDataSet;
  1124. begin
  1125.   Result := FQuery;
  1126. end;
  1127.  
  1128. procedure TQueryTableProducer.Notification(AComponent: TComponent; Operation: TOperation);
  1129. begin
  1130.   inherited Notification(AComponent, Operation);
  1131.   if (Operation = opRemove) and (AComponent = FQuery) then
  1132.     FQuery := nil;
  1133. end;
  1134.  
  1135. procedure TQueryTableProducer.SetDataSet(ADataSet: TDataSet);
  1136. begin
  1137.   SetQuery(ADataSet as TQuery);
  1138. end;
  1139.  
  1140. procedure TQueryTableProducer.SetQuery(AQuery: TQuery);
  1141. begin
  1142.   if FQuery <> AQuery then
  1143.   begin
  1144.     if AQuery <> nil then AQuery.FreeNotification(Self);
  1145.     FQuery := AQuery;
  1146.     InternalDataSource.DataSet := FQuery;
  1147.   end;
  1148. end;
  1149.  
  1150. { TDataSetTableProducer }
  1151.  
  1152. function TDataSetTableProducer.Content: string;
  1153. begin
  1154.   Result := '';
  1155.   if (FDataSet <> nil) and DoCreateContent then
  1156.     Result := FHeader.Text + HTMLTable(FDataSet, Self, FMaxRows) + FFooter.Text;
  1157. end;
  1158.  
  1159. function TDataSetTableProducer.GetDataSet: TDataSet;
  1160. begin
  1161.   Result := FDataSet;
  1162. end;
  1163.  
  1164. procedure TDataSetTableProducer.Notification(AComponent: TComponent; Operation: TOperation);
  1165. begin
  1166.   inherited Notification(AComponent, Operation);
  1167.   if (Operation = opRemove) and (AComponent = FDataSet) then
  1168.     FDataSet := nil;
  1169. end;
  1170.  
  1171. procedure TDataSetTableProducer.SetDataSet(ADataSet: TDataSet);
  1172. begin
  1173.   if FDataSet <> ADataSet then
  1174.   begin
  1175.     if ADataSet <> nil then ADataSet.FreeNotification(Self);
  1176.     FDataSet := ADataSet;
  1177.     InternalDataSource.DataSet := FDataSet;
  1178.   end;
  1179. end;
  1180.  
  1181. function HtmlTable(DataSet: TDataSet; DataSetHandler: TDSTableProducer;
  1182.   MaxRows: Integer): string;
  1183. const
  1184.   HTMLAlign: array[THTMLAlign] of string =
  1185.     ('',
  1186.      ' Align="Left"',
  1187.      ' Align="Right"',
  1188.      ' Align="Center"');
  1189.   HTMLVAlign: array[THTMLVAlign] of string =
  1190.     ('',
  1191.      ' VAlign="Top"',
  1192.      ' VAlign="Middle"',
  1193.      ' VAlign="Bottom"',
  1194.      ' VAlign="Basline"');
  1195.   Align: array[THTMLCaptionAlignment] of string =
  1196.     ('>',
  1197.      ' Align="Top">',
  1198.      ' Align="Bottom">');
  1199.   EndRow = '</TR>';
  1200. var
  1201.   I, J: Integer;
  1202.   DisplayText, RowHeaderStr: string;
  1203.   Field: TField;
  1204.   Column: THTMLTableColumn;
  1205.  
  1206.   function TableHeader: string;
  1207.   begin
  1208.     Result := '<Table';
  1209.     with DataSetHandler.TableAttributes do
  1210.     begin
  1211.       if Width > 0 then
  1212.         Result := Format('%s Width="%d%%"', [Result, Width]);
  1213.       Result := Result + HTMLAlign[Align];
  1214.       if CellSpacing > -1 then
  1215.         Result := Format('%s CellSpacing=%d', [Result, CellSpacing]);
  1216.       if CellPadding > -1 then
  1217.         Result := Format('%s CellPadding=%d', [Result, CellPadding]);
  1218.       if Border > -1 then
  1219.         Result := Format('%s Border=%d', [Result, Border]);
  1220.       if BgColor <> '' then
  1221.         Result := Format('%s BgColor="%s"', [Result, BgColor]);
  1222.       if Custom <> '' then
  1223.         Result := Format('%s %s', [Result, Custom]);
  1224.     end;
  1225.     Result := Result + '>';
  1226.   end;
  1227.  
  1228.   function TableCaption: string;
  1229.   var
  1230.     Caption: string;
  1231.     CaptionAlign: THTMLCaptionAlignment;
  1232.   begin
  1233.     Caption := DataSetHandler.Caption;
  1234.     CaptionAlign := DataSetHandler.CaptionAlignment;
  1235.     DataSetHandler.DoGetCaption(Caption, CaptionAlign);
  1236.     if Caption <> '' then
  1237.       Result := Format('<Caption %s%s</Caption>', [Align[CaptionAlign],Caption])
  1238.     else Result := '';
  1239.   end;
  1240.  
  1241.   function RowHeader: string;
  1242.   begin
  1243.     Result := '<TR';
  1244.     with DataSetHandler.RowAttributes do
  1245.     begin
  1246.       Result := Result + HTMLAlign[Align];
  1247.       Result := Result + HTMLVAlign[VAlign];
  1248.       if BgColor <> '' then
  1249.         Result := Format('%s BgColor="%s"', [Result, BgColor]);
  1250.       if Custom <> '' then
  1251.         Result := Format('%s %s', [Result, Custom]);
  1252.     end;
  1253.     Result := Result + '>';
  1254.   end;
  1255.  
  1256.   function FormatCell(CellRow, CellColumn: Integer; CellData: string;
  1257.     const Tag: string; const BgColor: THTMLBgColor; Align: THTMLAlign;
  1258.     VAlign: THTMLVAlign; const Custom: string): string;
  1259.   var
  1260.     CellAlign: THTMLAlign;
  1261.     CellVAlign: THTMLVAlign;
  1262.     CellBg: THTMLBgColor;
  1263.     CustomAttrs: string;
  1264.   begin
  1265.     Result := Format('<%s', [Tag]);
  1266.     CellBg := BgColor;
  1267.     CellAlign := Align;
  1268.     CellVAlign := VAlign;
  1269.     CustomAttrs := Custom;
  1270.     DataSetHandler.DoFormatCell(CellRow, CellColumn, CellBg, CellAlign,
  1271.       CellVAlign, CustomAttrs, CellData);
  1272.     Result := Result + HTMLAlign[CellAlign];
  1273.     Result := Result + HTMLVAlign[CellVAlign];
  1274.     if CellBg <> '' then
  1275.       Result := Format('%s BgColor="%s"', [Result, CellBg]);
  1276.     if CustomAttrs <> '' then
  1277.       Result := Format('%s %s', [Result, CustomAttrs]);
  1278.     Result := Result + Format('>%s</%s>', [CellData, Tag]);
  1279.   end;
  1280.  
  1281. begin
  1282.   RowHeaderStr := RowHeader;
  1283.   Result := TableHeader + TableCaption + #13#10 + RowHeaderStr;
  1284.   for I := 0 to DatasetHandler.Columns.Count - 1 do
  1285.   begin
  1286.     Column := DataSetHandler.Columns[I];
  1287.     Field := Column.Field;
  1288.     if Column.Title.Caption <> '' then
  1289.       DisplayText := Column.Title.Caption
  1290.     else if Field <> nil then
  1291.       DisplayText := Field.DisplayLabel
  1292.     else DisplayText := Column.DisplayName;
  1293.     with Column.Title do
  1294.       Result := Result + FormatCell(0, I, DisplayText, 'TH',
  1295.         BgColor, Align, VAlign, Custom);
  1296.   end;
  1297.   Result := Result + EndRow + #13#10;
  1298.   if DataSet.Active then
  1299.   begin
  1300.     J := 1;
  1301.     while (MaxRows <> 0) and not DataSet.EOF do
  1302.     begin
  1303.       Result := Result + RowHeaderStr;
  1304.       for I := 0 to DataSetHandler.Columns.Count - 1 do
  1305.       begin
  1306.         Column := DataSetHandler.Columns[I];
  1307.         Field := Column.Field;
  1308.         if Field <> nil then
  1309.           DisplayText := Field.DisplayText
  1310.         else DisplayText := '';
  1311.         with Column do
  1312.           Result := Result + FormatCell(J, I, DisplayText, 'TD',
  1313.             BgColor, Align, VAlign, Custom);
  1314.       end;
  1315.       Result := Result + EndRow + #13#10;
  1316.       DataSet.Next;
  1317.       Dec(MaxRows);
  1318.       Inc(J);
  1319.     end;
  1320.   end;
  1321.   Result := Result + '</Table>';
  1322. end;
  1323.  
  1324. end.
  1325.